package com.flow.demo.module.gd.service.gduser;

import cn.hutool.core.util.NumberUtil;
import com.alibaba.excel.util.DateUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.flow.demo.framework.common.pojo.PageResult;
import com.flow.demo.framework.common.util.object.BeanUtils;
import com.flow.demo.framework.web.core.util.WebFrameworkUtils;
import com.flow.demo.module.gd.controller.admin.user.vo.GdUserPageReqVO;
import com.flow.demo.module.gd.controller.admin.user.vo.GdUserSaveReqVO;
import com.flow.demo.module.gd.controller.app.gift.dto.GetVideoTimesDto;
import com.flow.demo.module.gd.controller.app.gift.dto.SaveAddressDto;
import com.flow.demo.module.gd.controller.app.gift.vo.SaveVideoTimeVo;
import com.flow.demo.module.gd.controller.app.user.dto.FullCondition;
import com.flow.demo.module.gd.controller.app.list.vo.ListSaveReqVO;
import com.flow.demo.module.gd.controller.app.user.dto.UploadImgDto;
import com.flow.demo.module.gd.controller.app.user.vo.*;
import com.flow.demo.module.gd.dal.dataobject.address.AddressDO;
import com.flow.demo.module.gd.dal.dataobject.gduser.GdUserDO;
import com.flow.demo.module.gd.dal.dataobject.list.ListDO;
import com.flow.demo.module.gd.dal.dataobject.userVideoTime.UserVideoTimeDO;
import com.flow.demo.module.gd.dal.mysql.address.AddressMapper;
import com.flow.demo.module.gd.dal.mysql.gduser.GdUserMapper;
import com.flow.demo.module.gd.dal.mysql.list.ListMapper;
import com.flow.demo.module.gd.dal.mysql.userVideoTime.UserVideoTimeMapper;
import com.flow.demo.module.gd.dal.redis.SendCodeRedisDAO;
import com.flow.demo.module.gd.service.list.ListService;
import com.flow.demo.module.gd.utils.FileUtils;
import com.flow.demo.module.system.api.sms.SmsCodeApi;
import com.flow.demo.module.system.api.sms.dto.code.SmsCodeSendReqDTO;
import com.flow.demo.module.system.enums.sms.SmsSceneEnum;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import static com.flow.demo.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.flow.demo.framework.common.util.servlet.ServletUtils.getClientIP;
import static com.flow.demo.module.gd.enums.ErrorCodeConstants.*;


/**
 * ppd筛查-监护人用户 Service 实现类
 *
 * @author pompey_hpy
 */
@Service
@Validated
public class GdUserServiceImpl implements GdUserService {

    @Resource
    private GdUserMapper gdUserMapper;


    @Value("${upload.file-path}")
    private String UPLOAD_FILE_PATH;

    @Value("${upload.visit-path}")
    private String UPLOAD_VISIT_PATH;

    @Value("${spring.profiles.active}")
    private String PROFILES_ACTIVE;

    @Resource
    private SmsCodeApi smsCodeApi;


    @Resource
    private SendCodeRedisDAO sendCodeRedisDAO;

    @Resource
    private UserVideoTimeMapper userVideoTimeMapper;

    @Resource
    private AddressMapper addressMapper;

    @Resource
    private ListMapper listMapper;


    @Override
    public UploadImgDto uploadImg(MultipartFile file, UploadImgVo vo) {
        UploadImgDto uploadImgDto = new UploadImgDto();

        String path = vo.getType() == 0 ? "/signature_file/" : "/avatar_file/";
        //图片保存 并生成路径
        String timeFileName = DateUtils.format(new Date(), com.alibaba.excel.util.DateUtils.DATE_FORMAT_10);
        //文件保存 并生成路径
        if (file != null) {
            String newName = FileUtils.upLoadFile(file, UPLOAD_FILE_PATH + path + timeFileName);
            String filePath = UPLOAD_VISIT_PATH + path + timeFileName + "/" + newName;
            uploadImgDto.setUrl(filePath);
        }
        return uploadImgDto;
    }

    @Override
    public void update(UpdateUserInfoVo updateReqVO) {
        GdUserDO gdUserDO = gdUserMapper.selectOne(GdUserDO::getId, updateReqVO.getId());
        if (gdUserDO == null)
            throw exception(GD_USER_NOT_EXISTS);

        GdUserDO updateUser = BeanUtils.toBean(updateReqVO, GdUserDO.class);
        updateUser.setUpdateTime(LocalDateTime.now());
        gdUserMapper.updateById(updateUser);
    }

    @Override
    public void sendCode(SendCodeVo vo) {
        String code = "123200";
        //发送短信逻辑，只有正式化环境下，才会发送短信
        if (PROFILES_ACTIVE.equals("prod"))
            code = smsCodeApi.sendSmsCode2(new SmsCodeSendReqDTO().setMobile(vo.getPhone()).setScene(SmsSceneEnum.MEMBER_LOGIN.getScene()).setCreateIp(getClientIP()));

        sendCodeRedisDAO.set(vo.getPhone(), code);

    }

    @Override
    public void bindPhone(BindPhoneVo vo) {
        String code = sendCodeRedisDAO.get(vo.getPhone());
        if (StringUtils.isEmpty(code))
            throw exception(CODE_LOSE);

        if (!code.equals(vo.getCode()))
            throw exception(CODE_ERROR);
        GdUserDO updateUser = new GdUserDO();
        updateUser.setId(vo.getId());
        updateUser.setPhone(vo.getPhone());
        updateUser.setUpdateTime(LocalDateTime.now());
        gdUserMapper.updateById(updateUser);
    }


    @Override
    public boolean verifyPhone(VerifyPhoneVo vo) {
        GdUserDO gdUserDO = gdUserMapper.selectOne(GdUserDO::getPhone, vo.getPhone());
        return gdUserDO == null;
    }

    @Override
    public boolean verifyCode(BindPhoneVo vo) {
        String code = sendCodeRedisDAO.get(vo.getPhone());
        if (StringUtils.isEmpty(code))
            throw exception(CODE_LOSE);

        if (!code.equals(vo.getCode()))
            throw exception(CODE_ERROR);

        sendCodeRedisDAO.delete(vo.getPhone());
        return true;
    }


    @Override
    public Integer createUser(GdUserSaveReqVO createReqVO) {
        // 插入
        GdUserDO user = BeanUtils.toBean(createReqVO, GdUserDO.class);
        gdUserMapper.insert(user);
        // 返回
        return user.getId();
    }

    @Override
    public void updateUser(GdUserSaveReqVO updateReqVO) {
        // 校验存在
        validateUserExists(updateReqVO.getId());
        // 更新
        GdUserDO updateObj = BeanUtils.toBean(updateReqVO, GdUserDO.class);
        gdUserMapper.updateById(updateObj);
    }

    @Override
    public void deleteUser(Integer id) {
        // 校验存在
        validateUserExists(id);
        // 删除
        gdUserMapper.deleteById(id);
    }

    private void validateUserExists(Integer id) {
        if (gdUserMapper.selectById(id) == null) {
            throw exception(GD_USER_NOT_EXISTS);
        }
    }

    @Override
    public GdUserDO getUser(Integer id) {
        return gdUserMapper.selectById(id);
    }

    @Override
    public PageResult<GdUserDO> getUserPage(GdUserPageReqVO pageReqVO) {
        return gdUserMapper.selectPage(pageReqVO);
    }

    @Override
    public GetVideoTimesDto getVideoTimes(Long loginUserId) {
        GetVideoTimesDto dto = new GetVideoTimesDto();
        dto.setUnuse(12);
        dto.setUsed(0);
        dto.setProgress(0);
        UserVideoTimeDO userVideoTimeDO = userVideoTimeMapper.selectOne(UserVideoTimeDO::getGdUserId, loginUserId);
        if (userVideoTimeDO != null) {
            dto.setTime(userVideoTimeDO.getTimes());
            dto.setVideo1(userVideoTimeDO.getVideo1() * 1000L);
            dto.setVideo2(userVideoTimeDO.getVideo2() * 1000L);
            dto.setVideo3(userVideoTimeDO.getVideo3() * 1000L);
            dto.setVideo4(userVideoTimeDO.getVideo4() * 1000L);
            dto.setVideo5(userVideoTimeDO.getVideo5() * 1000L);

            int used = userVideoTimeDO.getTimes() / 60;
            if (used >= 12) {
                dto.setUsed(12);
                dto.setUnuse(0);
                dto.setProgress(100);
            } else {
                dto.setUsed(used);
                dto.setUnuse(12 - used);
                int div3 = NumberUtil.div(used + "", "12", 2).multiply(BigDecimal.valueOf(100)).intValue();
                dto.setProgress(div3);
            }
        }

        return dto;
    }

    @Override
    public void saveVideoTime(SaveVideoTimeVo vo, Long loginUserId) {
        BigDecimal value = NumberUtil.div(vo.getTime() + "", "1000", 2);
        BigDecimal ceilingValue = value.setScale(0, RoundingMode.CEILING);
        int t = ceilingValue.intValue();
        UserVideoTimeDO update = new UserVideoTimeDO();
        UserVideoTimeDO userVideoTimeDO = userVideoTimeMapper.selectOne(UserVideoTimeDO::getGdUserId, loginUserId);
        if (userVideoTimeDO != null) {//修改
            update.setId(userVideoTimeDO.getId());
            switch (vo.getIndex()) {
                case 0:
                    update.setVideo1(t);
                    userVideoTimeDO.setVideo1(t);
                    break;
                case 1:
                    update.setVideo2(t);
                    userVideoTimeDO.setVideo2(t);
                    break;
                case 2:
                    update.setVideo3(t);
                    userVideoTimeDO.setVideo3(t);
                    break;
                case 3:
                    update.setVideo4(t);
                    userVideoTimeDO.setVideo4(t);
                    break;
                case 4:
                    update.setVideo5(t);
                    userVideoTimeDO.setVideo5(t);
                    break;
            }
            //计算总时长
            int countTime = userVideoTimeDO.getVideo1() + userVideoTimeDO.getVideo2() + userVideoTimeDO.getVideo3() + userVideoTimeDO.getVideo4() + userVideoTimeDO.getVideo5();
            update.setTimes(countTime);
            userVideoTimeMapper.updateById(update);
        } else {
            switch (vo.getIndex()) {
                case 0:
                    update.setVideo1(t);
                    break;
                case 1:
                    update.setVideo2(t);
                    break;
                case 2:
                    update.setVideo3(t);
                    break;
                case 3:
                    update.setVideo4(t);
                    break;
                case 4:
                    update.setVideo5(t);
                    break;
            }
            update.setGdUserId(loginUserId.intValue());
            update.setTimes(t);
            update.setCreateTime(LocalDateTime.now());
            userVideoTimeMapper.insert(update);
        }

    }

    @Override
    public void saveAddress(SaveAddressDto vo, Long loginUserId) {

        //查询是否已经填写
        AddressDO addressDO = addressMapper.selectOne(AddressDO::getGdUserId, loginUserId, AddressDO::getGdListId, vo.getListId());
        if (addressDO != null) {
            throw exception(ADDRESS_EXISTS);
        }

        //添加地址
        AddressDO insert = new AddressDO()
                .setName(vo.getName())
                .setPhone(vo.getPhone())
                .setGdListId(vo.getListId())
                .setGdUserId(loginUserId.intValue())
                .setAddress(vo.getAddress())
                .setCreateTime(LocalDateTime.now());
        addressMapper.insert(insert);

        //修改领取状态状态
        ListDO updateReqVO = new ListDO();
        updateReqVO.setId(vo.getListId());
        updateReqVO.setReceive(1);
        listMapper.updateById(updateReqVO);

    }

    private final Lock lock = new ReentrantLock();

    /**
     * @version: 2.0
     * @author: ak
     * @className: GdUserServiceImpl
     * @packageName: com.flow.demo.module.gd.service.gduser
     * @description: TODO 查看用户是否满足抽奖条件 (每次点抽奖触发)
     * @date: 2024/9/5
     **/
    @Override
    public FullCondition getFullCondition(Long loginUserId) {
        FullCondition fullCondition = new FullCondition();
        ListDO pojo = new ListDO();
        pojo.setGdUserId(loginUserId.intValue());
        pojo.setDate(LocalDate.now());
        //去中奖列表查找用户是否抽过奖品
        ListDO listDO = listMapper.selectOne(new QueryWrapper<ListDO>().lambda().eq(ListDO::getGdUserId, loginUserId.intValue()));
        if (Objects.nonNull(listDO)) {
            return fullCondition.setCondition(1);
        }
        //去视频时长表查询是否满足抽奖条件
        UserVideoTimeDO videoTimeDO = userVideoTimeMapper.selectOne(new QueryWrapper<UserVideoTimeDO>().lambda().eq(UserVideoTimeDO::getGdUserId, loginUserId.intValue()));
        if (Objects.nonNull(videoTimeDO)) {
            //总时长是否 大于等于 12分钟 （720秒）
            if (videoTimeDO.getTimes() >= 720) {
                // 第一个金融的视频是否看完 9分25秒  （565秒）   并且    第二个金融视频是否看完 3分 （180秒）
                // 没有抽过奖但是满足抽奖条件
                if (videoTimeDO.getVideo1() >= 565 || videoTimeDO.getVideo2() >= 180) {
                    synchronized (lock) {
                        ListDO goods = listMapper.selectOne(new QueryWrapper<ListDO>().lambda().eq(ListDO::getGdGoodId, 4));
                        if (Objects.isNull(goods)) {
                            //中奖
                            pojo.setGdGoodId(4);
                            int listId = listMapper.insert(pojo);
                            fullCondition.setListId(listId);
                            return fullCondition.setCondition(4);
                        } else {
                            //谢谢参与
                            pojo.setGdGoodId(6);
                            int listId = listMapper.insert(pojo);
                            fullCondition.setListId(listId);
                            //中奖
                            return fullCondition.setCondition(6);
                        }
                    }
                }
                //谢谢参与
                pojo.setGdGoodId(6);
                int listId = listMapper.insert(pojo);
                fullCondition.setListId(listId);
                return fullCondition.setCondition(6);
            }
        }

        //以上条件都不满足的话 乖乖去看视频
        return fullCondition.setCondition(3);
    }


}
